#coding=utf-8

import wx

import smtplib
import email.MIMEMultipart
import email.MIMEText
import email.MIMEBase

import os
import datetime

import subprocess
import myLogger

from product import *
from ConfTool27 import conf

class BackupManager:
    dbhost = "localhost"  
    dbname = "myshop"   # 数据库名 
    dbuser = "root"     # 用户名 
    dbuserpw = "agile"  # 密码 
    dbcharset = 'utf8'  # 输出文件编码，默认UTF8 
    dbport = 3308
       
    [SUCCEED, FAIL_EXPORT, FAIL_RAR, FAIL_EMAIL, FAIL_UNRAR, FAIL_IMPORT] = [i for i in range(6)]
    
    @classmethod
    def getConf(cls):
        cls.dbhost = conf.get_or_default('server', 'host', '127.0.0.1')
        cls.dbport = conf.getint('server', 'port', 3306)
        cls.dbname = conf.get_or_default('server', 'database', 'myshop')
        cls.dbuser = conf.get_or_default('server', 'username', 'root')
        cls.dbuserpw = conf.get_or_default('server', 'password', 'admin')
        #b_printer = conf.getint('basic', 'printer', 0)

    @classmethod
    def sendEmail(cls, file, user, psw):
        '''发送电子邮件'''
        retcode = cls.SUCCEED
        
        From = user
        To = user
        index = user.find('@') + 1
        smtpName = 'smtp.' + user[index:]

        try:
            #print smtpName
            server = smtplib.SMTP_SSL(smtpName)
            #print user
            #print psw
            server.login(user, psw)
            #print '3'
                
            main_msg = email.MIMEMultipart.MIMEMultipart()
            text_msg = email.MIMEText.MIMEText(u'【金博】个体户批发管理软件数据备份'.encode('gb2312'))
            main_msg.attach(text_msg)
            contype = 'application/octet-stream'
            maintype, subtype = contype.split('/', 1)

            #read tgzfile
            data = open(file, 'rb')
            file_msg = email.MIMEBase.MIMEBase(maintype, subtype)
            file_msg.set_payload(data.read())
            data.close()
            email.Encoders.encode_base64(file_msg)

            #set email header
            basename = os.path.basename(file)
            file_msg.add_header('Content-Disposition', 'attachment', filename=basename)
            main_msg.attach(file_msg)

            main_msg['From'] = From
            main_msg['To'] = To
            main_msg['Subject'] = u'【金博】个体户批发管理软件数据自动备份'.encode('gb2312')
            main_msg['Date'] = email.Utils.formatdate()

            fullText = main_msg.as_string()

            server.sendmail(From, To, fullText)
            server.quit()
        except Exception,e:
            myLogger.getLogger().error(str(e))
            retcode = cls.FAIL_EMAIL
            print(str(e))
        finally:
            #myLogger.getLogger().trace(u'释放邮件资源')
            #server.login()'s failure will raise smtpserverdisconnected
            #so do it in try:
            #server.quit()
            return retcode
        
    @classmethod
    def doShell(cls, cmd):
        '''替代os.system()'''
##        p = subprocess.Popen(cmd, shell=True)
##        sts = os.waitpid(p.pid, 0)[1]
        myLogger.getLogger().info(cmd)
        if isinstance(cmd, unicode):
            #python内部使用unicode编码，如果直接把命令发送到shell，会出现
            #中文路径乱码问题
            cmd = cmd.encode('gb2312')
            
        try:
            retcode = subprocess.call(cmd, shell=True)
            if retcode < 0:
                print >>sys.stderr, "Child was terminated by signal", -retcode
            else:
                print >>sys.stderr, "Child returned", retcode
        except OSError, e:
            print >>sys.stderr, "Execution failed:", e
        
        return retcode
       
    @classmethod
    def backupMySql(cls, dir):         
        if (dir[-1] == '\\'):
            backupFile = u'%s%s' %(dir, cls.getFileName())
        else:
            backupFile = u'%s\\%s' %(dir, cls.getFileName())

        print backupFile
        #如果目录不存在则创建之
        if not(os.path.exists(dir)):
            os.makedirs(dir)        
        
        #如果已经存在该文件则删除之
        if (os.path.isfile(backupFile)):
            if cls.doShell('del ' + backupFile) == 0:
                myLogger.getLogger().info('delete old file:%s!', backupFile)
        
        cls.getConf()
        #开始备份
        #不能换行
        cmd = '''mysqldump -B %s -h%s -u%s -p%s -P%d --default_character-set=%s --opt > %s\n''' %(
                cls.dbname, cls.dbhost, cls.dbuser, cls.dbuserpw, cls.dbport, cls.dbcharset, backupFile) 
        myLogger.getLogger().info(cmd)
        print(cmd)
        if cls.doShell(cmd) == 0:
            myLogger.getLogger().info('backup successfully:%s!', backupFile)
        else:
            myLogger.getLogger().error('backup Failed!!')
            return ''
            
        return backupFile
    
    @classmethod    
    def packFile(cls, file, psw):
        #删除旧的rar
        #tgzfile = '%s\%s_%s.rar' %(backup_path, dbname, now)
        tgzfile = file[:-3] + 'rar'
        if (os.path.isfile(tgzfile)):
            if cls.doShell('del ' + tgzfile) == 0:
                myLogger.getLogger().info('delete old file:%s!', file)
                
        #开始压缩
        cmd = "rar a -hp" + psw + " " + tgzfile + " " + file
        if cls.doShell(cmd) == 0:
            myLogger.getLogger().info( 'rar successfully!')
        else:
            myLogger.getLogger().error('rar Failed!!')
            return ''
        
        # 删除.sql
        #cls.doShell("del "+file)     # 140801
        #os.system("del "+file)
        return tgzfile
    
    @classmethod
    def getFileName(cls):
        name = str(datetime.datetime.now())[:16]
        name = name.replace(' ', '_')
        name = name.replace(':', '_')
        name = name.replace('-', '_')
        return name + '.bkp'
            
     
    @classmethod
    def makeBackup(cls, dir = ''):
        '''制作数据库备份
            先导出sql，然后rar，然后del sql，为了安全起见，rar失败也应该del sql
        '''
        backupCfg = CDataBackup.getBackupConfig()
        
        if (dir == ''):
            dir = backupCfg.getFieldVal(index=CDataBackup.COL_PATH)
            dir = dir.replace('/', '\\')
            
        #导出数据库
        file = cls.backupMySql(dir)
        if (file == ''):
            return (cls.FAIL_EXPORT, u'数据备份失败，可能是路径错误，请确保路径名中不含空格', '')
        
        #用rar打包
        code = backupCfg.getValue(CDataBackup.COL_CODE)
        tgzFile = cls.packFile(file, code)
        if (tgzFile == ''):
            return (cls.FAIL_RAR, u'文件压缩失败', '')

        # 为了避免暴露实现，无论有无rar都要删除.sql
        # 这样packFile()中的代码可以去除了
        # 2014-08-01
        cls.doShell("del "+file)  
        
        #保存lastfile，需要转换\为/
        file = tgzFile.replace('\\', '/')
        backupCfg.setMulFieldVal({CDataBackup.COL_LASTFILE:file})
        backupCfg.update([CDataBackup.COL_LASTFILE])
        
        #发送邮件
        if (backupCfg.getFieldVal(index=CDataBackup.COL_AUTOEMAIL) == 0):
            return (cls.SUCCEED, u'文件备份完成，没有发送邮件备份', tgzFile)
                
        user = backupCfg.getFieldVal(index=CDataBackup.COL_EMAIL)
        psw = backupCfg.getFieldVal(index=CDataBackup.COL_PSW)
        ret = cls.sendEmail(tgzFile, user, psw)
        if (ret == cls.SUCCEED):
            return (ret, u'文件备份完成，并且已经成功发送备份邮件', tgzFile)
        else:
            return (ret, u'文件备份完成，邮件备份失败', tgzFile)
    
    @classmethod        
    def unpackFile(cls, tgzFile, psw):      
        cmd = "rar e -o+ -p"+ psw + " " + tgzFile
        #cmd = 'unrar e -p123456 '+tgzfile+' '+backup_path
        if cls.doShell(cmd) == 0:
            myLogger.getLogger().info('unrar successfully!')
        else:
            myLogger.getLogger().error('unrar Failed!!')
            return ''
        
        file = os.getcwd()+'\\'+tgzFile[-21:-4]+'.bkp'
        return file

    @classmethod
    def loadBackup(cls, tgzFile, psw):
        file = cls.unpackFile(tgzFile, psw)
        if (file == ''):
            return (cls.FAIL_UNRAR, u'文件解压缩失败，可能是密码错误，请重新尝试')
        
        cls.getConf()
        cmd = "mysql -u%s -p%s -P%d < %s"  %(cls.dbuser, cls.dbuserpw, cls.dbport, file)
        print(cmd)
        if cls.doShell(cmd) == 0:
            myLogger.getLogger().info( 'recovery successfully!')
            retCode = cls.SUCCEED
            msg = u'完成数据恢复，请重新启动软件，以便正确显示'
        else:
            myLogger.getLogger().error('recovery Failed!!')
            retCode = cls.FAIL_IMPORT
            msg = u'导入数据失败'
        
        cls.doShell('del '+file)
        return (retCode, msg)
